using SanJ.FreeCare.Medications;
using Volo.Abp.EntityFrameworkCore.Modeling;
using Microsoft.EntityFrameworkCore;
using Volo.Abp.AuditLogging.EntityFrameworkCore;
using Volo.Abp.BackgroundJobs.EntityFrameworkCore;
using Volo.Abp.BlobStoring.Database.EntityFrameworkCore;
using Volo.Abp.Data;
using Volo.Abp.DependencyInjection;
using Volo.Abp.EntityFrameworkCore;
using Volo.Abp.FeatureManagement.EntityFrameworkCore;
using Volo.Abp.Identity;
using Volo.Abp.Identity.EntityFrameworkCore;
using Volo.Abp.LanguageManagement.EntityFrameworkCore;
using Volo.Abp.PermissionManagement.EntityFrameworkCore;
using Volo.Abp.SettingManagement.EntityFrameworkCore;
using Volo.Abp.TextTemplateManagement.EntityFrameworkCore;
using Volo.Saas.EntityFrameworkCore;
using Volo.Saas.Editions;
using Volo.Saas.Tenants;
using Volo.Abp.Gdpr;
using Volo.Abp.OpenIddict.EntityFrameworkCore;
using SanJ.FreeCare.ObservationDefinitions;
using SanJ.FreeCare.ObservationDefinitionItems;
using SanJ.FreeCare.ChargeItemDefinitions;
using SanJ.FreeCare.ChargeItems;
using SanJ.FreeCare.CodeSystems;

using SanJ.FreeCare.Conditions;
using SanJ.FreeCare.ConditionDefinitions;

using SanJ.FreeCare.Locations;

namespace SanJ.FreeCare.EntityFrameworkCore;

[ReplaceDbContext(typeof(IIdentityProDbContext))]
[ReplaceDbContext(typeof(ISaasDbContext))]
[ConnectionStringName("Default")]
public class FreeCareDbContext :
    AbpDbContext<FreeCareDbContext>,
    IIdentityProDbContext,
    ISaasDbContext
{
    public DbSet<Medication> Medications { get; set; } = null!;
    public DbSet<ObservationDefinition> ObservationDefinitions { get; set; } = null!;
    public DbSet<ObservationDefinitionItem> ObservationDefinitionItems { get; set; } = null!;
    public DbSet<ChargeItemDefinition> ChargeItemDefinitions { get; set; } = null!;
    public DbSet<ChargeItem> ChargeItems { get; set; } = null!;
    public DbSet<CodeSystem> CodeSystems { get; set; } = null!;
    public DbSet<Condition> Conditions { get; set; } = null !;
    public DbSet<ConditionDefinition> ConditionDefinitions { get; set; } = null!;
    public DbSet<Location> Locations { get; set; } = null!;
    //public DbSet<Applet> Applets { get; set; } = null!;
    /* Add DbSet properties for your Aggregate Roots / Entities here. */

    #region Entities from the modules

    /* Notice: We only implemented IIdentityProDbContext and ISaasDbContext
     * and replaced them for this DbContext. This allows you to perform JOIN
     * queries for the entities of these modules over the repositories easily. You
     * typically don't need that for other modules. But, if you need, you can
     * implement the DbContext interface of the needed module and use ReplaceDbContext
     * attribute just like IIdentityProDbContext and ISaasDbContext.
     *
     * More info: Replacing a DbContext of a module ensures that the related module
     * uses this DbContext on runtime. Otherwise, it will use its own DbContext class.
     */

    // Identity
    public DbSet<IdentityUser> Users { get; set; }
    public DbSet<IdentityRole> Roles { get; set; }
    public DbSet<IdentityClaimType> ClaimTypes { get; set; }
    public DbSet<OrganizationUnit> OrganizationUnits { get; set; }
    public DbSet<IdentitySecurityLog> SecurityLogs { get; set; }
    public DbSet<IdentityLinkUser> LinkUsers { get; set; }
    public DbSet<IdentityUserDelegation> UserDelegations { get; set; }

    // SaaS
    public DbSet<Tenant> Tenants { get; set; }
    public DbSet<Edition> Editions { get; set; }
    public DbSet<TenantConnectionString> TenantConnectionStrings { get; set; }

    #endregion

    public FreeCareDbContext(DbContextOptions<FreeCareDbContext> options)
        : base(options)
    {

    }

    protected override void OnModelCreating(ModelBuilder builder)
    {
        base.OnModelCreating(builder);

        /* Include modules to your migration db context */

        builder.ConfigurePermissionManagement();
        builder.ConfigureSettingManagement();
        builder.ConfigureBackgroundJobs();
        builder.ConfigureAuditLogging();
        builder.ConfigureIdentityPro();
        builder.ConfigureOpenIddictPro();
        builder.ConfigureFeatureManagement();
        builder.ConfigureLanguageManagement();
        builder.ConfigureSaas();
        builder.ConfigureTextTemplateManagement();
        builder.ConfigureBlobStoring();
        builder.ConfigureGdpr();

        /* Configure your own tables/entities inside here */

        //builder.Entity<YourEntity>(b =>
        //{
        //    b.ToTable(FreeCareConsts.DbTablePrefix + "YourEntities", FreeCareConsts.DbSchema);
        //    b.ConfigureByConvention(); //auto configure for the base class props
        //    //...
        //});

        builder.Entity<CodeSystem>(b =>
        {
            b.ToTable(FreeCareConsts.DbTablePrefix + "CodeSystems", FreeCareConsts.DbSchema);
            b.ConfigureByConvention();           
            b.OwnsMany(p => p.CodeConcepts).ToTable(FreeCareConsts.DbTablePrefix + "CodeSystemConcepts", FreeCareConsts.DbSchema);
        });

        builder.Entity<ChargeItem>(b =>
        {
            b.ToTable(FreeCareConsts.DbTablePrefix + "ChargeItems", FreeCareConsts.DbSchema);
            b.ConfigureByConvention();
            b.OwnsMany(p => p.Relations).ToTable(FreeCareConsts.DbTablePrefix + "ChargeItemsRelations", FreeCareConsts.DbSchema);
        });
        builder.Entity<ObservationDefinition>(b =>
        {
            b.ToTable(FreeCareConsts.DbTablePrefix + "ObservationDefinitions", FreeCareConsts.DbSchema);
            b.ConfigureByConvention();
        });
        builder.Entity<ConditionDefinition>(b =>
        {
            b.ToTable(FreeCareConsts.DbTablePrefix + "ConditionDefinitions", FreeCareConsts.DbSchema);
            b.ConfigureByConvention();
        });
        //builder.Entity<Applet>(b =>
        //{
        //    b.ToTable(FreeCareConsts.DbTablePrefix + "AppletRelations", FreeCareConsts.DbSchema);
        //    b.ConfigureByConvention();
        //});
        //builder.Entity<Location>(b =>
        //{
        //    b.ToTable(FreeCareConsts.DbTablePrefix + "Locations", FreeCareConsts.DbSchema);
        //    b.ConfigureByConvention();
        //});
        builder.Entity<ObservationDefinitionItem>(b =>
        {
            b.ToTable(FreeCareConsts.DbTablePrefix + "ObservationDefinitionItems", FreeCareConsts.DbSchema);
            b.ConfigureByConvention();
        });

        builder.Entity<ChargeItemDefinition>(b =>
        {
            b.ToTable(FreeCareConsts.DbTablePrefix + "ChargeItemDefinitions", FreeCareConsts.DbSchema);
            b.ConfigureByConvention();
            b.OwnsMany(p => p.Relations).ToTable(FreeCareConsts.DbTablePrefix + "ChargeItemDefinitionRelations", FreeCareConsts.DbSchema);
        });
        builder.Entity<Condition>(b =>
        {
            b.ToTable(FreeCareConsts.DbTablePrefix + "Conditions", FreeCareConsts.DbSchema);
            b.ConfigureByConvention();
            b.OwnsMany(p => p.ConditionRelations).ToTable(FreeCareConsts.DbTablePrefix + "ConditionRelations", FreeCareConsts.DbSchema);
        });
        builder.Entity<Medication>(b =>
            {
                b.ToTable(FreeCareConsts.DbTablePrefix + "Medications", FreeCareConsts.DbSchema);
                b.ConfigureByConvention();
                b.Property(x => x.TenantId).HasColumnName(nameof(Medication.TenantId));
                b.Property(x => x.Code).HasColumnName(nameof(Medication.Code));
                b.Property(x => x.StatusCode).HasColumnName(nameof(Medication.StatusCode));
                b.Property(x => x.KeyWord).HasColumnName(nameof(Medication.KeyWord));
                b.Property(x => x.ProductName).HasColumnName(nameof(Medication.ProductName));
                b.Property(x => x.ProductNamePY).HasColumnName(nameof(Medication.ProductNamePY));
                b.Property(x => x.ProductNameWB).HasColumnName(nameof(Medication.ProductNameWB));
                b.Property(x => x.ProductNameEN).HasColumnName(nameof(Medication.ProductNameEN));
                b.Property(x => x.Alias).HasColumnName(nameof(Medication.Alias));
                b.Property(x => x.AliasPY).HasColumnName(nameof(Medication.AliasPY));
                b.Property(x => x.AliasWB).HasColumnName(nameof(Medication.AliasWB));
                b.Property(x => x.AliasEN).HasColumnName(nameof(Medication.AliasEN));
                b.Property(x => x.ScientificName).HasColumnName(nameof(Medication.ScientificName));
                b.Property(x => x.ScientificNamePY).HasColumnName(nameof(Medication.ScientificNamePY));
                b.Property(x => x.ScientificNameWB).HasColumnName(nameof(Medication.ScientificNameWB));
                b.Property(x => x.ScientificNameEN).HasColumnName(nameof(Medication.ScientificNameEN));
                b.Property(x => x.AntiLevelCode).HasColumnName(nameof(Medication.AntiLevelCode));
                b.Property(x => x.AntiClassCode1).HasColumnName(nameof(Medication.AntiClassCode1));
                b.Property(x => x.AntiClassCode2).HasColumnName(nameof(Medication.AntiClassCode2));
                b.Property(x => x.AnitDDDUnitCode).HasColumnName(nameof(Medication.AnitDDDUnitCode));
                b.Property(x => x.AnitDDDValue).HasColumnName(nameof(Medication.AnitDDDValue));
                b.Property(x => x.AntiOnceMinValue).HasColumnName(nameof(Medication.AntiOnceMinValue));
                b.Property(x => x.AntiOnceMaxValue).HasColumnName(nameof(Medication.AntiOnceMaxValue));
                b.Property(x => x.AntiOnceUnitCode).HasColumnName(nameof(Medication.AntiOnceUnitCode));
                b.Property(x => x.AntiFrequencyMin).HasColumnName(nameof(Medication.AntiFrequencyMin));
                b.Property(x => x.AntiFrequencyMax).HasColumnName(nameof(Medication.AntiFrequencyMax));
                b.Property(x => x.GBCode).HasColumnName(nameof(Medication.GBCode));
                b.Property(x => x.TypeCode).HasColumnName(nameof(Medication.TypeCode));
                b.Property(x => x.ClassCode).HasColumnName(nameof(Medication.ClassCode));
                b.Property(x => x.FeeTypeCode).HasColumnName(nameof(Medication.FeeTypeCode));
                b.Property(x => x.SpecialTypeCode).HasColumnName(nameof(Medication.SpecialTypeCode));
                b.Property(x => x.LevelCode).HasColumnName(nameof(Medication.LevelCode));
                b.Property(x => x.DoseFormCode).HasColumnName(nameof(Medication.DoseFormCode));
                b.Property(x => x.Specification).HasColumnName(nameof(Medication.Specification));
                b.Property(x => x.BaseUnitCode).HasColumnName(nameof(Medication.BaseUnitCode));
                b.Property(x => x.ClinicSaleUnitCode).HasColumnName(nameof(Medication.ClinicSaleUnitCode));
                b.Property(x => x.ClinicSaleVolume).HasColumnName(nameof(Medication.ClinicSaleVolume));
                b.Property(x => x.InpatientSaleUnitCode).HasColumnName(nameof(Medication.InpatientSaleUnitCode));
                b.Property(x => x.InpatientSaleVolume).HasColumnName(nameof(Medication.InpatientSaleVolume));
                b.Property(x => x.TransportUnitCode).HasColumnName(nameof(Medication.TransportUnitCode));
                b.Property(x => x.TransportVolume).HasColumnName(nameof(Medication.TransportVolume));
                b.Property(x => x.DefaultDoseUnitCode).HasColumnName(nameof(Medication.DefaultDoseUnitCode));
                b.Property(x => x.DefultDoseVolume).HasColumnName(nameof(Medication.DefultDoseVolume));
                b.Property(x => x.SecondDoseUnitCode).HasColumnName(nameof(Medication.SecondDoseUnitCode));
                b.Property(x => x.SecondDoseVolume).HasColumnName(nameof(Medication.SecondDoseVolume));
                b.Property(x => x.RetailPrice).HasColumnName(nameof(Medication.RetailPrice));
                b.Property(x => x.DefaultUsageCode).HasColumnName(nameof(Medication.DefaultUsageCode));
                b.Property(x => x.DefaultFrequencyCode).HasColumnName(nameof(Medication.DefaultFrequencyCode));
                b.Property(x => x.DefaultDoseVolume).HasColumnName(nameof(Medication.DefaultDoseVolume));
                b.Property(x => x.SkinTestFlag).HasColumnName(nameof(Medication.SkinTestFlag));
                b.Property(x => x.SkinTestNeedFlag).HasColumnName(nameof(Medication.SkinTestNeedFlag));
                b.Property(x => x.SkinTestTypeFlag).HasColumnName(nameof(Medication.SkinTestTypeFlag));
                b.Property(x => x.SkinTestCode).HasColumnName(nameof(Medication.SkinTestCode));
                b.OwnsMany(x => x.ExtInfo);
            });
    }
}